package net.juntuo.amap;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.LOG;
import org.apache.cordova.PermissionHelper;
import org.apache.cordova.PluginResult;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.amap.api.location.AMapLocation;
import com.amap.api.location.AMapLocationClient;
import com.amap.api.location.AMapLocationClientOption;
import com.amap.api.location.AMapLocationClientOption.AMapLocationMode;
import com.amap.api.location.AMapLocationListener;
import com.amap.api.maps.AMap;
import com.amap.api.maps.CameraUpdateFactory;
import com.amap.api.maps.MapView;
import com.amap.api.maps.model.BitmapDescriptorFactory;
import com.amap.api.maps.model.LatLng;
import com.amap.api.maps.model.MarkerOptions;
import com.amap.api.maps.model.MultiPointItem;

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.text.TextPaint;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.widget.PopupWindow;

public class AmapLocation extends CordovaPlugin implements AMapLocationListener {

  MapView mapView = null;
  PopupWindow popupWindow = null;
  AMap aMap = null;

  String TAG = "GeolocationPlugin";
  String[] permissions = {Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION};

  private AMapLocationClient locationClient = null;
  private AMapLocationClientOption locationOption = null;
  boolean keepSendBack = false;
  CallbackContext callback;
  CallbackContext keepCallback;
  private Activity activity;

  private AMapLocationMode getAmapLocationMode(int mode) {
    switch (mode) {
      case 1:
        return AMapLocationMode.Hight_Accuracy;
      case 2:
        return AMapLocationMode.Device_Sensors;
      default:
        return AMapLocationMode.Battery_Saving;
    }
  }

  private void clearKeepLocationInstance() {
    if (locationClient != null) {
      locationClient.stopLocation();
      locationClient.onDestroy();
      locationClient = null;
      keepSendBack = false;
    }
  }

  private void config(JSONArray args) throws JSONException {
    this.clearKeepLocationInstance();
    if (locationClient == null) {
      Context context = this.cordova.getActivity().getApplicationContext();
      locationClient = new AMapLocationClient(context);
    }
    if (locationOption == null) {
      locationOption = new AMapLocationClientOption();
    }

    JSONObject params = new JSONObject(args.optString(0, "{}"));
    AMapLocationMode accuracy = this.getAmapLocationMode(params.optInt("androidAccuracy", 1));
    int interval = params.optInt("interval", 2000);
    boolean needAddress = params.optBoolean("needAddress", true);

    locationOption.setLocationMode(accuracy);
    locationClient.setLocationListener(this);
    locationOption.setNeedAddress(needAddress);
    locationOption.setInterval(interval);
    locationClient.setLocationOption(locationOption);
  }

  @Override
  public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
    callback = callbackContext;
    activity = this.cordova.getActivity();

    if ("getCurrentPosition".equals(action)) {
      this.config(args);
      //设置为单次定位
      locationOption.setOnceLocation(true);
      // 启动定位
      locationClient.startLocation();
      return true;
    } else if ("watchPosition".equals(action)) {
      keepCallback = callbackContext;

      this.config(args);
      //设置为多次定位
      locationOption.setOnceLocation(false);
      // 启动定位
      locationClient.startLocation();
      keepSendBack = true;

      return true;
    } else if ("clearWatch".equals(action)) {
      this.clearKeepLocationInstance();
      callback.success();
      return true;
    }else if ("showMap".equals(action)){
      JSONObject params = new JSONObject(args.optString(0, "{}"));
      double longitude = params.optDouble("longitude");
      double latitude = params.optDouble("latitude");
      int yaxis = params.optInt("yaxis");
      this.showMap(longitude,latitude,yaxis+24);
      return true;
    }else if ("hideMap".equals(action)){
      this.hideMap();
      return true;
    }else if ("addMarker".equals(action)){
      this.addMarker(args);
      return true;
    }else {
      return false;
    }
  }

  public void showMap(double longitude, double latitude, int yaxis) {
    Window window = activity.getWindow();
    Context context = this.cordova.getContext();
    View view = window.getDecorView();
    int top = fixAxis(context, yaxis);
    int width = view.getWidth();
    int height = view.getHeight()-top;

    mapView = new MapView(context);
    mapView.onCreate(null);
    aMap = mapView.getMap();
    LatLng latLng = new LatLng(latitude,longitude);
    aMap.moveCamera(CameraUpdateFactory.changeLatLng(latLng)); //设置中心点
    aMap.moveCamera(CameraUpdateFactory.zoomTo(18)); // 设置地图可视缩放大小

    activity.runOnUiThread(new Runnable() {
      @Override
      public void run() {
        popupWindow = new PopupWindow(mapView,width,height);
        popupWindow.showAtLocation(view,0,0, top);
      }
    });

    callback.success();
  }

  public void hideMap() {
    activity.runOnUiThread(new Runnable() {
      @Override
      public void run() {
        if (mapView != null) {
          mapView.onDestroy();
          mapView = null;
        }
        if (popupWindow != null) {
          popupWindow.dismiss();
          popupWindow = null;
        }
      }
    });
    callback.success();
  }

  public void addMarker(JSONArray args) throws JSONException {
    List<MultiPointItem> list = new ArrayList<MultiPointItem>();
    aMap.clear(true);
    for (int i=0; i<args.length(); i++){
      JSONObject jsonObject = args.getJSONObject(i);
      double longitude = jsonObject.optDouble("longitude");
      double latitude = jsonObject.optDouble("latitude");
      String marker = jsonObject.getString("marker");
      String name = jsonObject.getString("name");
      LatLng latLng = new LatLng(latitude,longitude);
      MarkerOptions markerOption = new MarkerOptions();
      markerOption.position(latLng);
      markerOption.icon(BitmapDescriptorFactory.fromBitmap(getMyBitmap(name,marker)));
      aMap.addMarker(markerOption);
    }
    callback.success();
  }

  protected Bitmap getMyBitmap(String pm_val,String marker) {
    int backResId = activity.getResources().getIdentifier(marker, "drawable", activity.getPackageName());
    Bitmap bitmap = BitmapDescriptorFactory.fromResource(backResId).getBitmap();
    bitmap = Bitmap.createScaledBitmap(bitmap, bitmap.getWidth() ,bitmap.getHeight(), false);
    Canvas canvas = new Canvas(bitmap);
    TextPaint textPaint = new TextPaint();
    textPaint.setAntiAlias(true);
    textPaint.setTextSize(38f);
    textPaint.setFakeBoldText(true);
    textPaint.setTextAlign(Paint.Align.CENTER);

    textPaint.setColor(Color.WHITE);
    textPaint.setStrokeWidth(4);
    textPaint.setStyle(Paint.Style.FILL_AND_STROKE);
    canvas.drawText(pm_val, bitmap.getWidth()/2, 86 ,textPaint); // 设置bitmap上面的文字描边

    textPaint.setColor(Color.argb(0xff, 0x33, 0, 0));
    textPaint.setStrokeWidth(0);
    textPaint.setStyle(Paint.Style.FILL_AND_STROKE);
    canvas.drawText(pm_val, bitmap.getWidth()/2, 86 ,textPaint); // 设置bitmap上面的文字显示

    return bitmap;
  }

  protected static int fixAxis(Context context, float value) {
    final float scale = context.getResources().getDisplayMetrics().density;
    return (int) (value * scale + 0.5f);
  }

  @Override
  public void onLocationChanged(AMapLocation aMapLocation) {
    if (aMapLocation != null) {
      if (aMapLocation.getErrorCode() == 0) {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = new Date(aMapLocation.getTime());
        df.format(date);//定位时间

        JSONObject locationInfo = new JSONObject();
        try {
          locationInfo.put("locationType", aMapLocation.getLocationType()); //获取当前定位结果来源，如网络定位结果，详见定位类型表
          locationInfo.put("latitude", aMapLocation.getLatitude()); //获取纬度
          locationInfo.put("longitude", aMapLocation.getLongitude()); //获取经度
          locationInfo.put("accuracy", aMapLocation.getAccuracy()); //获取精度信息
          locationInfo.put("speed", aMapLocation.getSpeed()); //获取速度信息
          locationInfo.put("bearing", aMapLocation.getBearing()); //获取方向信息
          locationInfo.put("date", date); //定位时间
          locationInfo.put("address", aMapLocation.getAddress()); //地址，如果option中设置isNeedAddress为false，则没有此结果
          locationInfo.put("country", aMapLocation.getCountry()); //国家信息
          locationInfo.put("province", aMapLocation.getProvince()); //省信息
          locationInfo.put("city", aMapLocation.getCity()); //城市信息
          locationInfo.put("district", aMapLocation.getDistrict()); //城区信息
          locationInfo.put("street", aMapLocation.getStreet()); //街道信息
          locationInfo.put("streetNum", aMapLocation.getStreetNum()); //街道门牌号
          locationInfo.put("cityCode", aMapLocation.getCityCode()); //城市编码
          locationInfo.put("adCode", aMapLocation.getAdCode()); //地区编码
          locationInfo.put("poiName", aMapLocation.getPoiName());
          locationInfo.put("aoiName", aMapLocation.getAoiName());
          locationInfo.put("floor", aMapLocation.getFloor()); //获取当前室内定位的楼层
        } catch (JSONException e) {
          Log.e(TAG, "Locatioin json error:" + e);
        }
        PluginResult result = new PluginResult(PluginResult.Status.OK, locationInfo);
        if (!keepSendBack) { //不持续传回定位信息
          locationClient.stopLocation(); //只获取一次的停止定位
        } else {
          result.setKeepCallback(true);
        }
        keepCallback.sendPluginResult(result);
      } else {
        //显示错误信息ErrCode是错误码，errInfo是错误信息，详见错误码表。
        Log.e(TAG, "Locatioin error:" + aMapLocation.getErrorCode());
        PluginResult result = new PluginResult(PluginResult.Status.ERROR, aMapLocation.getErrorCode());
        keepCallback.sendPluginResult(result);
      }
    }
  }


  public void onRequestPermissionResult(int requestCode, String[] permissions,
                                        int[] grantResults) throws JSONException {
    PluginResult result;
    //This is important if we're using Cordova without using Cordova, but we have the geolocation plugin installed
    if (callback != null) {
      for (int r : grantResults) {
        if (r == PackageManager.PERMISSION_DENIED) {
          LOG.d(TAG, "Permission Denied!");
          result = new PluginResult(PluginResult.Status.ILLEGAL_ACCESS_EXCEPTION);
          callback.sendPluginResult(result);
          return;
        }

      }
      result = new PluginResult(PluginResult.Status.OK);
      callback.sendPluginResult(result);
    }
  }

  public boolean hasPermisssion() {
    for (String p : permissions) {
      if (!PermissionHelper.hasPermission(this, p)) {
        return false;
      }
    }
    return true;
  }

  /*
   * We override this so that we can access the permissions variable, which no longer exists in
   * the parent class, since we can't initialize it reliably in the constructor!
   */

  public void requestPermissions(int requestCode) {
    PermissionHelper.requestPermissions(this, requestCode, permissions);
  }
}
